<template>
  <div ref="list" @scroll="handleScroll" class="infinite-list-container">
    <div
      class="infinite-list-phantom"
      :style="{ height: listHeight + 'px' }"
    ></div>
    <div class="infinite-list" :style="{ transform }">
      <div
        ref="items"
        class="infinite-list-item"
        v-for="item in visibleData"
        :key="item.id"
      >
        项目--{{ item }}
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onMounted, ref } from 'vue'

export default defineComponent({
  name: 'Home',

  setup () {
    const list = ref(null)
    const listData = ref([])
    const itemSize = ref(30)
    const screenHeight = ref(0)
    const startOffset = ref(0)
    const startIndex = ref(0)
    const endIndex = ref(0)
    const bufferScale = ref(1)

    const listHeight = computed(() => {
      return listData.value.length * itemSize.value
    })
    const transform = computed(() => {
      return `translateY(${startOffset.value}px)`
    })
    const visibleCount = computed(() => {
      return Math.ceil(screenHeight.value / itemSize.value)
    })
    const aboveCount = computed(() => {
      return Math.min(startIndex.value, bufferScale.value * visibleCount.value)
    })
    const belowCount = computed(() => {
      return Math.min(listData.value.length - endIndex.value, bufferScale.value * visibleCount.value)
    })

    const visibleData = computed(() => {
      const star = startIndex.value - aboveCount.value
      const end = endIndex.value + belowCount.value
      return listData.value.slice(
        star,
        end,
      )
    })

    function getData () {
      for (let i = 0; i < 100; i++) {
        listData.value.push(i)
      }
    }
    function handleScroll (e) {
      // console.log('scroll', e.target.scrollTop)
      const scrollTop = Math.min(e.target.scrollTop, listHeight.value - screenHeight.value)
      startIndex.value = Math.floor(scrollTop / itemSize.value)
      endIndex.value = startIndex.value + visibleCount.value
      startOffset.value = scrollTop - (scrollTop % itemSize.value)
    }

    onMounted(() => {
      screenHeight.value = list.value.clientHeight
      startIndex.value = 0
      endIndex.value = startIndex.value + visibleCount.value
      // console.log('JS运行时间：', Date.now() - now)
      getData()
      // setTimeout(() => {
      //   console.log('总运行时间：', Date.now() - now)
      // }, 0)
    })
    return {
      list,
      listData,
      itemSize,
      listHeight,
      transform,
      visibleData,
      handleScroll,
    }
  },
})
</script>

<style scoped>
.infinite-list-container {
  height: calc(100vh - 50px);
  overflow: auto;
  position: relative;
  -webkit-overflow-scrolling: touch;
}

.infinite-list-phantom {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  z-index: -1;
}

.infinite-list {
  left: 0;
  right: 0;
  top: 0;
  position: absolute;
  text-align: center;
}

.infinite-list-item {
  padding: 10px;
  color: #555;
  box-sizing: border-box;
  border-bottom: 1px solid #999;
}
</style>
